/*
* ============================================================================
*  Name        : sea_memtracker.cpp
*  Part of     : Finite state machine utilities
*  Description : 
*  Version     : %version: %
*  
*
* ============================================================================
*/
#include "sea_memtracker.h"
#include "sea_trace.h"

/**
 * @file sea_memtracker.cpp
 * @brief
 *  Memory tracking helper class implementation
 *
 * @ingroup DebugUtilities
 */
using namespace sea;
using namespace std;

// -------------------------------------------------------------------------------------------------

#if defined( DEBUG )

map< void*, MemoryBlock* > g_mem_stat;

int MemoryBlock::m_allocations_counter = 0;
int MemoryBlock::m_releases_counter = 0;

long long MemoryBlock::m_max_memory_allocated = 0;
long long MemoryBlock::m_total_memory_allocated = 0;

OsMutex MemoryBlock::m_lock;

// -------------------------------------------------------------------------------------------------
// Add memory block to the statistics list
// -------------------------------------------------------------------------------------------------
void MemoryBlock::add( void* ptr, int size, int line, const char* file ) 
{
    OsMutex::Scoped safe( &m_lock );

    ++m_allocations_counter;
    m_total_memory_allocated += size;

    if ( m_max_memory_allocated < m_total_memory_allocated )
    {
        m_max_memory_allocated = m_total_memory_allocated;
    }

    MemoryBlock* block = ::new MemoryBlock( ptr, size, line, file );
    g_mem_stat[ ptr ] = block;
}

// -------------------------------------------------------------------------------------------------
// Remove memory block from the statistics list
// -------------------------------------------------------------------------------------------------
void MemoryBlock::remove( void* ptr ) 
{
    OsMutex::Scoped safe( &m_lock );

    ++m_releases_counter;
    MemoryBlock* block = g_mem_stat[ ptr ];
    if ( block )
    {
        m_total_memory_allocated -= block->m_size;
    }
    g_mem_stat.erase( ptr );
    delete block;
}

// -------------------------------------------------------------------------------------------------
// Print list of allocated memory blocks
// -------------------------------------------------------------------------------------------------
bool MemoryBlock::print_stats( )
{
    OsMutex::Scoped scoped( &m_lock );

    SEA_TRACE( "Total allocations: %d Max memory allocated: %d", m_allocations_counter, m_max_memory_allocated );

    if ( g_mem_stat.size( ) ) 
    {
        SEA_TRACE( "MEMORY LEAK(S):" );
        SEA_TRACE( "-------------------------------------------------------" );
        
        long total = 0;

        for( map< void*, MemoryBlock* >::iterator it = g_mem_stat.begin( ); it != g_mem_stat.end( ); ++it )
        {
            MemoryBlock* block = ( *it ).second;
            Object* obj = reinterpret_cast< Object*> ( block->m_ptr );
            SEA_TRACE( "LEAK: addr %x %s @ %d  sz: %d refs:%d ", obj, block->m_file, block->m_line, block->m_size, obj->refs( ) );

            total += block->m_size;
        }
        SEA_TRACE( "-------------------------------------------------------" );
        SEA_TRACE( "Blocks: %d", g_mem_stat.size( ) );
        SEA_TRACE( "Total: %d bytes", total );
        SEA_TRACE( "-------------------------------------------------------" );

        ASSERT_DEBUG( g_mem_stat.size( ) == 0 );

        return false;
    }
    SEA_TRACE( "!!!! GOOD JOB!!! NO MEMORY LEAKS!!!" );
    return true;
}

#endif

// -------------------------------------------------------------------------------------------------
